package cn.iocoder.yudao.module.shop.info.service;

import cn.iocoder.yudao.framework.business.audit.enums.AuditStatusEnum;
import cn.iocoder.yudao.framework.business.basic.dao.repository.SerialNoRedisRepository;
import cn.iocoder.yudao.framework.business.order.pojo.vo.OrderSubmitVO;
import cn.iocoder.yudao.framework.common.exception.KnownServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.api.pay.order.PayOrderApi;
import cn.iocoder.yudao.module.api.pay.order.dto.PayOrderCreateDTO;
import cn.iocoder.yudao.module.api.pay.order.eums.UnifiedOrderStatusEnum;
import cn.iocoder.yudao.module.api.pay.order.vo.PayOrderVO;
import cn.iocoder.yudao.module.api.shop.ConfigConstants;
import cn.iocoder.yudao.module.shop.info.convert.ShopEnterOrderConvert;
import cn.iocoder.yudao.module.shop.info.dal.dataobject.ShopEnterOrderDO;
import cn.iocoder.yudao.module.shop.info.dal.dataobject.ShopEnterPackageDO;
import cn.iocoder.yudao.module.shop.info.dal.dataobject.ShopInfoDO;
import cn.iocoder.yudao.module.shop.info.dal.mysql.ShopEnterOrderMapper;
import cn.iocoder.yudao.module.shop.info.dal.mysql.ShopEnterPackageMapper;
import cn.iocoder.yudao.module.shop.info.dal.mysql.ShopInfoMapper;
import cn.iocoder.yudao.module.shop.info.vo.AppShopEnterOrderCreateReqVO;
import cn.iocoder.yudao.module.shop.info.vo.ShopEnterOrderPageReqVO;
import cn.iocoder.yudao.module.shop.info.vo.ShopEnterPackageUpdateReqVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.Objects;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserLastShopId;
import static cn.iocoder.yudao.module.api.shop.ErrorCodeConstants.*;

/**
 * 店铺入驻缴费 Service 实现类
 *
 * @author 山野羡民（1032694760@qq.com）
 */
@Service
@Validated
@Slf4j
public class ShopEnterOrderServiceImpl implements ShopEnterOrderService {

    @Resource
    private ShopEnterOrderMapper shopEnterOrderMapper;
    @Resource
    private ShopEnterPackageMapper shopEnterPackageMapper;
    @Resource
    private ShopInfoMapper shopInfoMapper;
    @Resource
    private SerialNoRedisRepository serialNoRedisRepository;
    @Resource
    private ShopInfoService shopInfoService;
    @Resource
    private PayOrderApi payOrderApi;

    @Override
    public ShopEnterOrderDO getEnterOrder(Long id) {
        return validateEnterOrderExists(id);
    }

    @Override
    public PageResult<ShopEnterOrderDO> getEnterOrderPage(ShopEnterOrderPageReqVO pageReqVO) {
        return shopEnterOrderMapper.selectPage(pageReqVO);
    }

    @Override
    public ShopEnterOrderDO getMyEnterOrder() {
        return shopEnterOrderMapper.selectOne(ShopEnterOrderDO::getShopId, getLoginUserLastShopId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderSubmitVO submitEnterOrder(AppShopEnterOrderCreateReqVO reqVO) {
        // 校验店铺信息
        ShopInfoDO shopInfoDO = validShopInfo(getLoginUserLastShopId());
        // 校验是否存在未支付的套餐
        ShopEnterOrderDO shopEnterOrderDO = shopEnterOrderMapper.selectOne(ShopEnterOrderDO::getShopId, shopInfoDO.getId(),
                ShopEnterOrderDO::getEnterPackageId, reqVO.getEnterPackageId(),
                ShopEnterOrderDO::getPayed, false);
        ShopEnterPackageDO enterPackageDO = validateEnterPackage(reqVO.getEnterPackageId());
        // 不存在未支付的套餐，则创建
        if (shopEnterOrderDO == null) {
            // 校验店铺入驻套餐信息
            shopEnterOrderDO = new ShopEnterOrderDO();
            shopEnterOrderDO.setTradeNo(serialNoRedisRepository.generateNo(ConfigConstants.ENTER_ORDER_NO_PREFIX));
            shopEnterOrderDO.setShopId(shopInfoDO.getId());
            shopEnterOrderDO.setEnterPackageId(enterPackageDO.getId());
            shopEnterOrderDO.setRemark(reqVO.getRemark());
            shopEnterOrderMapper.insert(shopEnterOrderDO);
            // 创建店铺缴费订单后再创建付款单据
            PayOrderCreateDTO createDTO = ShopEnterOrderConvert.INSTANCE.convert(enterPackageDO, shopEnterOrderDO);
            payOrderApi.createOrder(createDTO);
        }
        // 存在未支付的套餐，则直接返回付款单据
        OrderSubmitVO respVO = new OrderSubmitVO();
        respVO.setTradeNo(shopEnterOrderDO.getTradeNo());
        respVO.setPrice(enterPackageDO.getPrice());
        return respVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrderPaid(String tradeNo, String payNo) {
        ShopEnterOrderDO shopEnterOrderDO = validateEnterOrderExists(tradeNo);
        // 校验店铺入驻缴费是否已支付
        if (shopEnterOrderDO.getPayed()) {
            throw new KnownServiceException(ENTER_ORDER_UPDATE_PAID_STATUS_IS_PAID);
        }
        // 若店铺入驻缴费未支付，则从支付单中获取支付状态
        PayOrderVO orderVO = payOrderApi.getOrderByNo(tradeNo);
        if (orderVO == null || !UnifiedOrderStatusEnum.isSuccess(orderVO.getStatus())) {
            throw exception(ENTER_ORDER_UPDATE_PAID_PAY_ORDER_UNPAID);
        }
        // 若支付单中是已支付，则同步更新支付状态
        shopEnterOrderDO.setPayed(true);
        //shopEnterOrderDO.setPayNo(payNo);
        shopEnterOrderMapper.updateById(shopEnterOrderDO);
        // 若支付单中是已支付，则同步更新店铺入驻套餐信息
        ShopEnterPackageUpdateReqVO reqVO = new ShopEnterPackageUpdateReqVO();
        reqVO.setId(shopEnterOrderDO.getShopId());
        reqVO.setEnterPackageId(shopEnterOrderDO.getEnterPackageId());
        shopInfoService.updateEnterPackage(reqVO);
    }

    private ShopInfoDO validShopInfo(Long shopId) {
        ShopInfoDO shopInfoDO = shopInfoMapper.selectOne(ShopInfoDO::getId, shopId);
        if (shopInfoDO == null) {
            throw exception(SHOP_INFO_NOT_EXISTS);
        }
        if (Objects.equals(shopInfoDO.getAuditStatus(), AuditStatusEnum.WAIT.getValue())) {
            throw exception(SHOP_INFO_AUDIT_WAIT);
        }
        if (Objects.equals(shopInfoDO.getAuditStatus(), AuditStatusEnum.REJECT.getValue())) {
            throw exception(SHOP_INFO_AUDIT_FAIL, shopInfoDO.getAuditNote());
        }
        return shopInfoDO;
    }

    private ShopEnterPackageDO validateEnterPackage(Long id) {
        ShopEnterPackageDO enterPackageDO = shopEnterPackageMapper.selectById(id);
        if (enterPackageDO == null) {
            throw exception(ENTER_PACKAGE_NOT_EXISTS);
        }
        return enterPackageDO;
    }

    private ShopEnterOrderDO validateEnterOrderExists(Long id) {
        ShopEnterOrderDO shopEnterOrderDO = shopEnterOrderMapper.selectById(id);
        if (shopEnterOrderDO == null) {
            throw exception(ENTER_ORDER_NOT_EXISTS);
        }
        return shopEnterOrderDO;
    }

    private ShopEnterOrderDO validateEnterOrderExists(String no) {
        ShopEnterOrderDO shopEnterOrderDO = shopEnterOrderMapper.selectOne(ShopEnterOrderDO::getTradeNo, no);
        if (shopEnterOrderDO == null) {
            throw exception(ENTER_ORDER_NOT_EXISTS);
        }
        return shopEnterOrderDO;
    }

}
